/*
** phcstd.h
** 
** Made by Michael DuPont
** Login   <mdupont@mdupontdesktop2>
** 
** Started on  Sat Mar 14 22:23:36 2009 Michael DuPont
** Last update Sat Mar 14 22:23:36 2009 Michael DuPont
*/

#ifndef   	PHCSTD_H_
# define   	PHCSTD_H_

/*
 * The runtime needs its own initialization and finalization.  phc is
 * responsible for generating calls to these functions.
 */

void
init_runtime ();

void
finalize_runtime ();

void
ht_debug (HashTable * ht);

// Call ht_debug on the named var in the given symbol table
void
ht_var_debug (HashTable * st, char *name);

 void init_counters ();

// Dump and cleanup memory
 void finalize_counters ();

 void increment_counter (char* name, int length, ulong hashval);



/* Make a copy of *P_ZVP, storing it in *P_ZVP. */
zvalP
zvp_clone_ex (zvalP zvp);

int in_copy_on_write (zvalP zvp);

int in_change_on_write (zvalP zvp);

/* If *P_ZVP is in a copy-on-write set, separate it by overwriting
 * *P_ZVP with a clone of itself, and lowering the refcount on the
 * original. */
 void
sep_copy_on_write (zvalPP p_zvp);

/* If *P_ZVP is in a copy-on-write set, separate it by overwriting
 * *P_ZVP with a clone of itself, and lowering the refcount on the
 * original. */
 void
sep_change_on_write (zvalPP p_zvp);

/* Assign RHS into LHS, by reference. After this, LHS will point to the same
 * zval* as RHS. */
 void
copy_into_ref (zvalPP lhs, zvalPP rhs);

// Overwrite one zval with another
void
overwrite_lhs (zvalP lhs, zvalP rhs);

// Overwrite one zval with another
void
overwrite_lhs_no_copy (zvalP lhs, zvalP rhs);

/* Write P_RHS into the symbol table as a variable named VAR_NAME. */
// NOTE: We do not alter p_rhs's refcount, unless p_lhs joins its
// Copy-on-write set.
// TODO: this is crying out to be inlined.
void
write_var (zvalPP p_lhs, zvalP rhs);

// TODO: this functino does too much, and much might be redundant
zvalPP
get_st_entry (HashTable * st, char *name, int length, ulong hashval TSRMLS_DC);

/* Read the variable named VAR_NAME from the local symbol table and
 * return it. If the variable doent exist, a new one is created and
 * *IS_NEW is set.  */
zvalP
read_var (HashTable * st, char *name, int length, ulong hashval TSRMLS_DC);

long
get_integer_index (zvalP ind TSRMLS_DC);

zvalP
read_string_index (zvalP var, zvalP ind TSRMLS_DC);

/* Given a string (p_lhs), write into it for $x[i] = $y; */
void
write_string_index (zvalPP p_lhs, zvalP ind, zvalP rhs TSRMLS_DC);

// Extract the hashtable from a hash-valued zval
HashTable *
extract_ht_ex (zvalP arr TSRMLS_DC);


/* P_VAR points into a symbol table, at a variable which we wish to index as a hashtable. */
HashTable *
extract_ht (zvalPP p_var TSRMLS_DC);

/* Using IND as a key to HT, call the appropriate zend_index_X
 * function with data as a parameter, and return its result. This
 * updates the zval** pointed to by DATA. */
int
ht_find (HashTable * ht, zvalP ind, zvalPPP data);


int
check_array_index_type (zvalP ind TSRMLS_DC);

// Update a hashtable using a zval* index
void
ht_update (HashTable * ht, zvalP ind, zvalP val, zvalPPP dest);

// Delete from a hashtable using a zval* index
void
ht_delete (HashTable * ht, zvalP ind);

// Check if a key exists in a hashtable 
int
ht_exists (HashTable * ht, zvalP ind);

zvalPP
get_ht_entry (zvalPP p_var, zvalP ind TSRMLS_DC);


// Like extract_ht_ex, but for objects 
HashTable *
extract_field_ex (zvalP obj TSRMLS_DC);

// Like extract_ht, but for objects
HashTable *
extract_field (zvalPP p_var TSRMLS_DC);

// Like get_ht_entry, but for objects
zvalPP
get_field (zvalPP p_var, char *ind TSRMLS_DC);

void
read_array (zvalPP result, zvalP array, zvalP ind TSRMLS_DC);

/* If its not an array, convert it into an array. */
void
check_array_type (zvalPP p_var TSRMLS_DC);

/* If its not an array, convert it into an object. */
void
check_object_type (zvalPP p_var TSRMLS_DC);

/* Push EG (uninitialized_zval_ptr) and return a pointer into the ht
 * for it */
/*
 * Converted to array automatically:
 *    ""
 *    NULL
 *    false
 *
 * Warning, no conversion:
 *    ints
 *    floats
 *    true
 *
 * Error, no conversion:
 *    strings other than ""
 */
// TODO: objects, resources, etc
zvalPP
push_and_index_ht (zvalPP p_var TSRMLS_DC);


/*
 * isset
 */
int
isset_var (HashTable * st, char *name, int length);

int
isset_array (zvalPP p_var, zvalP ind);


zvalPP
fetch_var_arg_by_ref (zvalPP p_arg);

/* Dont pass-by-ref */
zvalP
fetch_var_arg (zvalP arg, int *is_arg_new);

// TODO dont overwrite line numbers if we're compiling an extension
void
phc_setup_error (int init, char *filename, int line_number,
		 zend_function * function TSRMLS_DC);

 void
initialize_function_call (zend_fcall_info * fci, zend_fcall_info_cache * fcic,
			  char *function_name, char *filename,
			  int line_number TSRMLS_DC);

/*
 * Initialize zend_fcall_info for a method lookup
 *
 * Implementation partly based on zend_call_method in Zend/zend_interfaces.c
 * Main difference is that we use Z_OBJ_HTT_PP(obj)->get_method to retrieve
 * the function handler for the method instead of looking it up directly;
 * this means that we correctly deal with __call.
 */

 void
initialize_method_call (zend_fcall_info * fci, zend_fcall_info_cache * fcic,
			zvalPP obj, char *function_name,
			char *filename, int line_number TSRMLS_DC);

/*
 * Like initialize_method_call, but return 0 if no constructor is defined
 * rather than giving an error.
 */

 int 
initialize_constructor_call (zend_fcall_info * fci,
			     zend_fcall_info_cache * fcic, zvalPP obj,
			     char *filename, int line_number TSRMLS_DC);

/*
 * Creates a copy of *in using persistent memory, optionally destroying *in
 *
 * Does not work for objects/resources and will loop on self-recursive arrays.
 */

zvalP
persistent_clone (zvalP in, int destroy_in TSRMLS_DC);
/*
 * Wrapper around zend_declare_property which 
 *
 * - Asserts that the ZEND_INTERNAL_CLASS flag is cleared
 *   (otherwise we cannot add complex (i.e., array) properties)
 * - Creates a persistent clone of the property to be added before
 *   calling zend_declare_property, since the memory for this property
 *   should only be deallocated when the module is shut down
 *   (and not when the request finishes)
 * - Cleans up after zend_declare_property by re-allocating the name of 
 *   the property using persistent memory, for much the same reason
 */

int
phc_declare_property (zend_class_entry * ce, char *name, int name_length,
		      zvalP property, int access_type TSRMLS_DC);


void
cast_var (zvalPP p_zvp, int type);

/* Copies a constant into ZVP. Note that LENGTH does not include the NULL-terminating byte. */
void
get_constant (char *name, int length, zvalPP p_zvp TSRMLS_DC);

/* The function call mechanism deals specially with EG(uninitialize_zval_ptr)
 * (or sometime EG(uninitialize_zval)), so we need to use this too. This
 * particular zval can also be set, but there is an implicit guarantee 
 * of the information below.
 *
 * If assertions are off, this should be inlined to nothing.
 */
/*void
phc_check_invariants (TSRMLS_D);
*/

int
check_unset_index_type (zvalP ind TSRMLS_DC);



/*
 * unset
 */

void
unset_var (HashTable * st, char *name, int length);

void
unset_array (zvalPP p_var, zvalP ind TSRMLS_DC);

/*
 * Lookup variable whose name is var_var in st. We do not call
 * ht_find because ht_find uses zend_symtable_find to search for strings
 * rather than zend_hash_find. The difference is that zend_symtable_find
 * will convert strings to integers where possible: arrays are always
 * integer-indexed if at all possible. Variable names however should
 * _always_ be treated as strings.
 * 
 */

/*
 * If the parameter is a string, returns the parameter, with the refcount
 * incremented. If its not a string, returns a new zval, with a refcount of
 * 1. Either way, zval_dtor_ptr must be run by the caller on the return
 * value.
 */
zvalP
get_string_val (zvalP zvp);

zvalPP
get_var_var (HashTable * st, zvalP index TSRMLS_DC);
/* 
 * Read the variable described by var_var from symbol table st
 * See comments for get_var_var
 */
zvalP
read_var_var (HashTable * st, zvalP index TSRMLS_DC);

void
phc_builtin_eval (zvalP arg, zvalPP p_result, char *filename TSRMLS_DC);

void
phc_builtin_exit (zvalP arg, zvalPP p_result, char *filename TSRMLS_DC);

void
phc_builtin_die (zvalP arg, zvalPP p_result, char *filename TSRMLS_DC);

void
phc_builtin_echo (zvalP arg, zvalPP p_result TSRMLS_DC);

void
phc_builtin_print (zvalP arg, zvalPP p_result, char *filename TSRMLS_DC);

// TODO is there a memory leak here is result has a value?
// TOOD isnt this just the same as isset
void phc_builtin_empty (zvalP arg, zvalPP p_result, char *filename TSRMLS_DC);


// For require, include, require_once and include_once.

// Include:
//    return 1 for success
//    Warning, and return false for failure
// Require:
//    return 1 for success
//    Fail for failure
// Include_once
//    Return true if already included
//    Return 1 for success
//    Warning and return false for failure
// Require_once:
//    Return true if already included
//    return 1 for success
//    Fail for failure
//

void include_backend (zvalP arg, zvalPP p_result, char *filename, int type, int is_once, char* error, char* error_function TSRMLS_DC);
void phc_builtin_include (zvalP arg, zvalPP p_result, char *filename TSRMLS_DC);
void phc_builtin_require (zvalP arg, zvalPP p_result, char *filename TSRMLS_DC);
void phc_builtin_include_once (zvalP arg, zvalPP p_result, char *filename TSRMLS_DC);
void phc_builtin_require_once (zvalP arg, zvalPP p_result, char *filename TSRMLS_DC);


#endif 	    /* !PHCSTD_H_ */
